package com.muatocroi.tornado;

import java.util.Timer;
import java.util.TimerTask;

import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class ProcessTouchPad implements OnTouchListener {
	private static final int INVALID_POINTER_ID = -1;
	static float lastMoveX, lastMoveY;
	static float lastScrollX, lastScrollY;
	static long downTime;
	static boolean isDowning = false;
	static boolean isScrolling = false;
	static Timer timerWaitClick = null;
	static SignalSender sender = null;
	static ProcessTouchPad _instance = null;
	static boolean isWaitingClick = false;
	static int idLButton = INVALID_POINTER_ID;
	static int idRButton = INVALID_POINTER_ID;
	static int idMoving = INVALID_POINTER_ID;
	static int idScrolling = INVALID_POINTER_ID;
	static ViewTouchPad viewer = null;

	private ProcessTouchPad() {
		
	}

	private static void setWaitClick() {
		timerWaitClick = new Timer();
		TimerTask taskClickTask = new TimerTask() {
			public void run() {
				sender.Send(CommandMouse.LeftClick());
				isWaitingClick = false;
				timerWaitClick.cancel();
				timerWaitClick.purge();
			}
		};
		timerWaitClick.schedule(taskClickTask, 100);
		isWaitingClick = true;
	}

	private static void cancelWaitClick() {
		timerWaitClick.cancel();
		timerWaitClick.purge();
		isWaitingClick = false;
	}

	public static ProcessTouchPad instance() {
		if (_instance == null)
			_instance = new ProcessTouchPad();
		return _instance;
	}

	public static void setSender(SignalSender sender) {
		ProcessTouchPad.sender = sender;
	}

	public static void setTouchView(View v) {
		v.setOnTouchListener(ProcessTouchPad.instance());
		viewer = (ViewTouchPad) v;
	}

	@Override
	public boolean onTouch(View v, MotionEvent e) {
		int actIndex = e.getActionIndex();
		int x = (int) e.getX(actIndex);
		int y = (int) e.getY(actIndex);
		int pid = e.getPointerId(actIndex);

		switch (e.getAction() & MotionEvent.ACTION_MASK) {
         
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_POINTER_1_DOWN:
		case MotionEvent.ACTION_POINTER_2_DOWN:
		case MotionEvent.ACTION_POINTER_3_DOWN:
		
			if (viewer.rectMove.contains(x, y)) {
				idMoving = pid;
				downTime = System.currentTimeMillis();
				if (isWaitingClick) {
					cancelWaitClick();
					sender.Send(CommandMouse.LeftDown());
					isDowning = true;
				}
				lastMoveX = x;
				lastMoveY = y;
			} else if (viewer.rectScroll.contains(x, y)) {
				idScrolling = pid;
				if (!viewer.isScrolling) {
					viewer.isScrolling = true;
					viewer.invalidate();
				}
				lastScrollY = y;
				idScrolling = pid;
			} else if (viewer.rectLButton.contains((int) x, (int) y)) {
				idLButton = pid;
				if (!viewer.isLeftDowning) {
					sender.Send(CommandMouse.LeftDown());
					viewer.isLeftDowning = true;
					viewer.invalidate();
				}
			} else if (viewer.rectRButton.contains((int) x, (int) y)) {
				idRButton = pid;
				if (!viewer.isRightDowning) {
					sender.Send(CommandMouse.RightDown());
					viewer.isRightDowning = true;
					viewer.invalidate();
				}
			}
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_1_UP:
		case MotionEvent.ACTION_POINTER_2_UP:
		case MotionEvent.ACTION_POINTER_3_UP:
			if (pid == idLButton) {
				sender.Send(CommandMouse.LeftUp());
				viewer.isLeftDowning = false;
				viewer.invalidate();
				idLButton = INVALID_POINTER_ID;
			} else if (pid == idRButton) {
				sender.Send(CommandMouse.RightUp());
				viewer.isRightDowning = false;
				viewer.invalidate();
				idRButton = INVALID_POINTER_ID;
			} else if (pid == idMoving) {
				if (isDowning) {
					sender.Send(CommandMouse.LeftUp());
					isDowning = false;
					if (System.currentTimeMillis() - downTime < 100)
						if (isLastLocation(x, y))
							sender.Send(CommandMouse.LeftClick());
				} else {
					if (System.currentTimeMillis() - downTime < 100)
						if (isLastLocation(x, y))
							setWaitClick();
				}
				idMoving = INVALID_POINTER_ID;
			} else if (pid == idScrolling) {
				viewer.isScrolling = false;
				viewer.invalidate();
				idScrolling = INVALID_POINTER_ID;
			}
			break;

		case MotionEvent.ACTION_MOVE:
			int c = e.getPointerCount();
			for (int p = 0; p < c; p++) {
				pid = e.getPointerId(p);
				x = (int) e.getX(p);
				y = (int) e.getY(p);
				if (pid == idMoving) {
					short dx = (short) ((x - lastMoveX) * 1.5);
					short dy = (short) ((y - lastMoveY) * 1.5);
					sender.Send(CommandMouse.Move(dx, dy));
					lastMoveX = x;
					lastMoveY = y;
					break;
				} else if (pid == idScrolling) {
					short sline = (short) ((lastScrollY - y) * 0.2);
					sender.Send(CommandMouse.VScroll((byte) sline));
					lastScrollY = y;
					break;
				}
			}
			break;
		}

		return true;
	}

	private boolean isLastLocation(int x, int y) {
		return (Math.abs(x - lastMoveX) < 5 && Math.abs(y - lastMoveY) < 5);
	}
}
